package city.spring.modules.bed.service.impl;

import city.spring.modules.bed.entity.*;
import city.spring.modules.bed.service.*;
import city.spring.modules.bed.vo.BedInfoVO;
import city.spring.utils.TreeDataUtils;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 公寓管理
 *
 * @author HouKunLin
 * @date 2020/8/6 0006 16:46
 */
@CacheConfig(cacheNames = {BedManagementService.CACHE_NAME})
@Transactional(rollbackFor = Throwable.class)
@Service
public class BedManagementServiceImpl implements BedManagementService {
    private final BedBuildingService bedBuildingService;
    private final BedFloorService bedFloorService;
    private final BedRoomService bedRoomService;
    private final BedService bedService;

    public BedManagementServiceImpl(BedBuildingService bedBuildingService, BedFloorService bedFloorService, BedRoomService bedRoomService, BedService bedService) {
        this.bedBuildingService = bedBuildingService;
        this.bedFloorService = bedFloorService;
        this.bedRoomService = bedRoomService;
        this.bedService = bedService;
    }

    /**
     * 获得老人床位信息
     *
     * @param oldmanId 老人ID
     * @return 床位信息
     * @deprecated 过时的方法，老人与床位关联关系已经改变，该方法无法正确获取到数据
     */
    @Deprecated
    @Cacheable(key = "methodName+':oldmanId='+#oldmanId")
    @Override
    public BedInfoVO getOldmanBed(String oldmanId) {
        BedInfoVO vo = new BedInfoVO();
        BedEntity bedEntity = bedService.lambdaQuery().eq(BedEntity::getOldmanId, oldmanId).one();
        if (bedEntity == null) {
            bedEntity = BedEntity.EMPTY;
        }
        getBedInfo(bedEntity, vo);
        return vo;
    }

    @Cacheable(key = "methodName+':loadBed='+#loadBed")
    @Override
    public List<BaseStruct> getAllData(boolean loadBed) {
        List<BaseStruct> list = new ArrayList<>();
        list.addAll(bedBuildingService.list());
        list.addAll(bedFloorService.list());
        list.addAll(bedRoomService.list());
        if (loadBed) {
            list.addAll(bedService.list());
        }
        return list;
    }

    @Cacheable(key = "methodName+':loadBed='+#loadBed")
    @Override
    public ListMultimap<String, BaseStruct> getAllTreeData(boolean loadBed) {
        return TreeDataUtils.handlerTreeDatasource(getAllData(loadBed), "", BaseStruct::getId, BaseStruct::getPid, BaseStruct::getChildren, BaseStruct::setChildren);
    }

    @Override
    public ListMultimap<String, BedEntity> getBedMultimap() {
        // 获取所有房间列表
        List<BedEntity> roomEntities = bedService.list();
        // 以 楼层ID 为键，收集每一个楼层的房间列表信息
        ListMultimap<String, BedEntity> multimap = ArrayListMultimap.create();

        roomEntities.forEach(entity -> multimap.put(entity.getBedRoomId(), entity));

        return multimap;
    }

    @Cacheable(key = "methodName+':hashCode='+#bedMultimap?.hashCode()?:0")
    @Override
    public ListMultimap<String, BedRoomEntity> getFloorRoomMultimap(ListMultimap<String, BedEntity> bedMultimap) {
        // 获取所有房间列表
        List<BedRoomEntity> roomEntities = bedRoomService.list();

        BiConsumer<ListMultimap<String, BedEntity>, BedRoomEntity> loadChildren = (multimap, entity) -> {
            List<BedEntity> entities = multimap.get(entity.getId());
            // 重新对列表进行排序
            entities.sort(Comparator.comparing(BedEntity::getGmtCreate, Date::compareTo));
            entity.setChildren(entities);
        };

        // 以 楼层ID 为键，收集每一个楼层的房间列表信息
        ListMultimap<String, BedRoomEntity> multimap = ArrayListMultimap.create();

        for (BedRoomEntity entity : roomEntities) {
            if (bedMultimap != null) {
                loadChildren.accept(bedMultimap, entity);
            }
            multimap.put(entity.getBedFloorId(), entity);
        }
        return multimap;
    }

    @Cacheable(key = "methodName+':hashCode='+#floorRoomMultimap?.hashCode()?:0")
    @Override
    public ListMultimap<String, BedFloorEntity> getFloorMultimap(ListMultimap<String, BedRoomEntity> floorRoomMultimap) {
        // 获取所有楼层列表
        List<BedFloorEntity> floorEntities = bedFloorService.list();

        BiConsumer<ListMultimap<String, BedRoomEntity>, BedFloorEntity> loadChildren = (multimap, entity) -> {
            List<BedRoomEntity> entities = multimap.get(entity.getId());
            // 重新对列表进行排序
            entities.sort(Comparator.comparing(BedRoomEntity::getGmtCreate, Date::compareTo));
            entity.setChildren(entities);
        };

        // 以 楼栋ID 为键，收集每一个楼栋的楼层列表信息
        ListMultimap<String, BedFloorEntity> multimap = ArrayListMultimap.create();
        for (BedFloorEntity entity : floorEntities) {
            if (floorRoomMultimap != null) {
                loadChildren.accept(floorRoomMultimap, entity);
            }
            multimap.put(entity.getBedBuildingId(), entity);
        }

        return multimap;
    }

    @Cacheable(key = "methodName+':hashCode='+#floorMultimap?.hashCode()?:0")
    @Override
    public List<BedBuildingEntity> getBuildingList(ListMultimap<String, BedFloorEntity> floorMultimap) {
        List<BedBuildingEntity> buildingEntities = bedBuildingService.list();
        if (floorMultimap != null) {
            buildingEntities.forEach(entity -> {
                List<BedFloorEntity> entities = floorMultimap.get(entity.getId());
                // 重新对列表进行排序
                entities.sort(Comparator.comparing(BedFloorEntity::getGmtCreate, Date::compareTo));
                entity.setChildren(entities);
            });
        }
        return buildingEntities;
    }

    @Override
    public BedInfoVO getBedInfo(String bedId) {
        BedInfoVO vo = new BedInfoVO();
        BedEntity bedEntity = bedService.getById(bedId);
        if (bedEntity == null) {
            bedEntity = new BedEntity();
            bedEntity.setCode("0");
            bedEntity.setName("<未找到>");
        }
        getBedInfo(bedEntity, vo);
        return vo;
    }

    @Override
    public List<BedInfoVO> getBedInfoByBedIds(List<String> bedIds) {
        if (bedIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<BedEntity> bedEntities = bedService.listByIds(bedIds);
        List<BedRoomEntity> roomEntities = bedRoomService.listByIds(bedEntities, BedEntity::getBedRoomId);
        List<BedFloorEntity> floorEntities = bedFloorService.listByIds(roomEntities, BedRoomEntity::getBedFloorId);
        List<BedBuildingEntity> buildingEntities = bedBuildingService.listByIds(floorEntities, BedFloorEntity::getBedBuildingId);
        Map<String, BedRoomEntity> roomEntityMap = roomEntities.stream().collect(Collectors.toMap(BaseStruct::getId, Function.identity()));
        Map<String, BedFloorEntity> floorEntityMap = floorEntities.stream().collect(Collectors.toMap(BaseStruct::getId, Function.identity()));
        Map<String, BedBuildingEntity> buildingEntityMap = buildingEntities.stream().collect(Collectors.toMap(BaseStruct::getId, Function.identity()));
        List<BedInfoVO> list = new ArrayList<>();
        for (BedEntity bedEntity : bedEntities) {
            BedInfoVO vo = new BedInfoVO();
            BedRoomEntity roomEntity = roomEntityMap.getOrDefault(bedEntity.getBedRoomId(), BedRoomEntity.EMPTY);
            BedFloorEntity floorEntity = floorEntityMap.getOrDefault(roomEntity.getBedFloorId(), BedFloorEntity.EMPTY);
            BedBuildingEntity buildingEntity = buildingEntityMap.getOrDefault(floorEntity.getBedBuildingId(), BedBuildingEntity.EMPTY);
            vo.setBed(bedEntity);
            vo.setRoom(roomEntity);
            vo.setFloor(floorEntity);
            vo.setBuilding(buildingEntity);
            list.add(vo);
        }
        return list;
    }

    private void getBedInfo(BedEntity bedEntity, BedInfoVO vo) {
        BedRoomEntity roomEntity = bedRoomService.lambdaQuery().eq(BedRoomEntity::getId, bedEntity.getBedRoomId()).one();
        if (roomEntity == null) {
            roomEntity = BedRoomEntity.EMPTY;
        }
        BedFloorEntity floorEntity = bedFloorService.lambdaQuery().eq(BedFloorEntity::getId, roomEntity.getBedFloorId()).one();
        if (floorEntity == null) {
            floorEntity = BedFloorEntity.EMPTY;
        }
        BedBuildingEntity buildingEntity = bedBuildingService.lambdaQuery().eq(BedBuildingEntity::getId, floorEntity.getBedBuildingId()).one();
        if (buildingEntity == null) {
            buildingEntity = BedBuildingEntity.EMPTY;
        }
        vo.setBed(bedEntity);
        vo.setRoom(roomEntity);
        vo.setFloor(floorEntity);
        vo.setBuilding(buildingEntity);
    }
}
